package com.xcity.game.activity.sevendays;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.xcity.db.entity.Player;
import com.xcity.game.activity.ActivityService;
import com.xcity.game.activity2.ActivityIds;
import com.xcity.game.common.Cause;
import com.xcity.game.common.MessageConst;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.event.GameEvents;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.push.msg.ActivityStatePush;
import com.xcity.pomelo.push.msg.TipPush;
import com.xcity.pomelo.request.SevenDaysInfoRequest;
import com.xcity.pomelo.request.SevenDaysReSignInRequest;
import com.xcity.pomelo.request.SevenDaysSignInRequest;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.pomelo.response.SevenDaysInfoResponse;
import com.xcity.pomelo.response.SevenDaysResignInResponse;
import com.xcity.pomelo.response.SevenDaysSignInResponse;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.ServiceException;
import naga.x.util.TimeUtils;

/**
 * 七日签到
 * @author yang.li
 *
 */
@OPHandler
public class SevenDaysSignInActivityService extends ActivityService implements EventListener {

	private List<SevenDaysSignInTemplate> templates;
	private Map<Long, List<SevenDay>> sevenDays = new ConcurrentHashMap<Long, List<SevenDay>>(128);
	private static final int MAX_RESIGN_TIMES = 2; // 每7天最大补签次数
	private static final int[] RESIGN_COST_STONE = new int[] { 5, 10 }; // 补签消耗钻石(第一次: 5, 第二次: 10)
	
	@Override
	public void startup() throws ServiceException {
		templates = App.getApp().getServiceManager().get(TemplateService.class).getTemplatesList(SevenDaysSignInTemplate.class);
		App.getApp().getEventManager().register(this);
	}

	@Override
	public void shutdown() throws ServiceException {
	}

	@Override
	public int[] getEventTypes() {
		return new int[]{ GameEvents.EVENT_PLAYER_LOGIN,
				GameEvents.EVENT_PLAYER_LOADED,
				GameEvents.EVENT_PLAYER_LOGOUT };
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.getType()) {
			case GameEvents.EVENT_PLAYER_LOGIN:
				playerLogin(event.getParameter());
				break;
			case GameEvents.EVENT_PLAYER_LOADED:
				playerLoaded(event.getParameter());
				break;
			case GameEvents.EVENT_PLAYER_LOGOUT:
				playerLogout(event.getParameter());
				break;
		}
	}
	
	public void playerLoaded(Player player){
//		int today = TimeUtils.getDayGap(player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY), TimeUpdater.getInstance().today());
//		//TimeUpdater.getInstance().today() - player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY);
//		List<SevenDay> list = getSevenDayList(player);
//		if(today > -1 && today < list.size()){
//			SevenDay sd = list.get(today);
//			if(sd.getState() == SevenDay.STATE_NO_SIGN){
//				player.send(new ActivityStatePush(ActivityIds.ACTIVITY_7DAY_SIGN, STATE_OPENED));
//			}
//		}
	}
	
	public List<SevenDay> playerLogin(Player player) {
		if (needReset(player)) {
			return reset(player);
		}
		byte[] states = player.getPool().getObject(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN, byte[].class);
		return init(player, states);
	}
	
	private List<SevenDay> init(Player player, byte[] states) {
		List<SevenDay> list = new ArrayList<SevenDay>(7);
		for (int i = 0, len = states != null ? states.length : 0; i < 7; i++) {
			byte state = i < len ? states[i] : SevenDay.STATE_NO_SIGN;
			SevenDay sd = new SevenDay(templates.get(i), state);
			list.add(sd);
		}
		sevenDays.put(player.getId(), list);
		return list;
	}
	
	private boolean needReset(Player player) {
		int firstDay = player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY);
		return firstDay == 0 || TimeUtils.getDayGap(firstDay, TimeUpdater.getInstance().today()) >= 7;//TimeUpdater.getInstance().today() - firstDay >= 7
	}
	
	private List<SevenDay> reset(Player player) {
		player.poolSet(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY, TimeUpdater.getInstance().today());
		byte[] states = new byte[7];
		Arrays.fill(states, SevenDay.STATE_NO_SIGN);
		player.poolSet(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN, states);
		player.poolRemove(PlayerPool.PROPERTY_SEVEN_DAYS_RESIGNED_TIMES);
		return init(player, states);
	}
	
	void playerLogout(Player player) {
		sevenDays.remove(player.getId());
	}
	
	private List<SevenDay> getSevenDayList(Player player) {
		if (needReset(player)) {
			return reset(player);
		}
		List<SevenDay> list = sevenDays.get(player.getId());
		return list != null ? list : playerLogin(player);
	}
	
	private static int getLeftResignInTimes(Player player) {
		int n = MAX_RESIGN_TIMES - player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_RESIGNED_TIMES);
		return n > 0 ? n : 0;
	}
	
	private static int getResignCostStone(Player player) {
		int[] cost = RESIGN_COST_STONE;
		int len = cost.length;
		int n = player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_RESIGNED_TIMES);
		return n >= 0 && n < len ? cost[n] : cost[len - 1];
	}
	
	@PomeloOP(PomeloRoute.SEVEN_DAYS_INFO)
	protected void requestInfo(Session session, SevenDaysInfoRequest req) {
		Player player = session.getClient();
		int leftResignTimes = getLeftResignInTimes(player);
		int resignCost = getResignCostStone(player);
		List<SevenDay> list = getSevenDayList(player);
		// 今天应签到天数
		int today = TimeUtils.getDayGap(player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY), TimeUpdater.getInstance().today()) + 1;
		//TimeUpdater.getInstance().today() - player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY) + 1;
		SevenDaysInfoResponse res = new SevenDaysInfoResponse(req.getSerial(), leftResignTimes, resignCost, today, list);
		session.send(res);
	}
	
	@PomeloOP(PomeloRoute.SEVEN_DAYS_SIGN_IN)
	protected void requestSignIn(Session session, SevenDaysSignInRequest req) {
		Player player = session.getClient();
		List<SevenDay> list = getSevenDayList(player);
		int index = TimeUtils.getDayGap(player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY), TimeUpdater.getInstance().today());
		//TimeUpdater.getInstance().today() - player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY);
		if (index < 0 || index >= list.size()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.SYSTEM_ERROR));
			return;
		}
		SevenDay sd = list.get(index);
		if (sd.getState() != SevenDay.STATE_NO_SIGN) {
			session.send(new HintResponse(req.getSerial(), MessageConst.SIGNED_TODAY));
			return;
		}
		// 检测背包剩余空间
		int needBagGridSize = sd.getTemplate().isAutoUse() ? 0 : (sd.getCount() + sd.getTemplate().getStack() - 1) / sd.getTemplate().getStack();
		if (player.getBag().getFreeSize() < needBagGridSize) {
			session.send(new HintResponse(req.getSerial(), MessageConst.BAG_FULL));
			return;
		}
		sd.setState(SevenDay.STATE_SIGNED);
		byte[] states = player.getPool().getObject(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN, byte[].class);
//		if (states == null) { // 不可能有这种情况
//			states = wrapList(list);
//			player.getPool().put(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN, states);
//		}
		states[index] = SevenDay.STATE_SIGNED; // 同步pool
		player.getBag().addItemWithoutException(sd.getId(), sd.getCount(), Cause.SEVEN_DAYS_SIGN);
		session.send(new SevenDaysSignInResponse(req.getSerial(), index + 1));
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_DAILY_SIGN, player);
		LOG.info("[7DAYSIGN]ID[{}]DAY[{}]ITEM[{}]COUNT[{}]", player.getId(), index, sd.getId(), sd.getCount());
//		player.send(new ActivityStatePush(ActivityIds.ACTIVITY_7DAY_SIGN, STATE_CLOSED));
	}

	@PomeloOP(PomeloRoute.SEVEN_DAYS_RESIGN_IN)
	protected void requestReSignIn(Session session, SevenDaysReSignInRequest req) {
		Player player = session.getClient();
		int leftTimes = getLeftResignInTimes(player);
		if (leftTimes == 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.RESIGN_TIMES_ZERO));
			return;
		}
		int index = req.getDay() - 1;
		List<SevenDay> list = getSevenDayList(player);
		if (index < 0 || index >= list.size()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ILLEGAL_OPERATION));
			return;
		}
		int maxIndex = TimeUtils.getDayGap(player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY), TimeUpdater.getInstance().today());
		//TimeUpdater.getInstance().today() - player.getPool().getIntValue(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN_FIRST_DAY);
		if (index >= maxIndex) {
			session.send(new HintResponse(req.getSerial(), MessageConst.CAN_NOT_RESIGN));
			return;
		}
		SevenDay sd = list.get(index);
		if (sd.getState() != SevenDay.STATE_NO_SIGN) {
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.DONOT_NEED_RESIGN, req.getDay())));
			return;
		}
		// 检测背包剩余空间
		int needBagGridSize = sd.getTemplate().isAutoUse() ? 0 : (sd.getCount() + sd.getTemplate().getStack() - 1) / sd.getTemplate().getStack();
		if (player.getBag().getFreeSize() < needBagGridSize) {
			session.send(new HintResponse(req.getSerial(), MessageConst.BAG_FULL));
			return;
		}
//		new ResignOperation(player, index, sd, resignCost).send();
		
		if (sd.getState() != SevenDay.STATE_NO_SIGN) {
			player.send(new TipPush(MessageFormat.format(MessageConst.DONOT_NEED_RESIGN, index + 1)));
			return;
		}
		int resignCost = getResignCostStone(player);
		if (!player.costStone(resignCost, Cause.SEVEN_DAYS_RESIGN)) {
			return;
		}
		sd.setState(SevenDay.STATE_SIGNED);
		byte[] states = player.getPool().getObject(PlayerPool.PROPERTY_SEVEN_DAYS_LOGIN, byte[].class);
		states[index] = SevenDay.STATE_SIGNED; // 同步pool
		player.poolAdd(PlayerPool.PROPERTY_SEVEN_DAYS_RESIGNED_TIMES, 1); // 同步增加补签次数
		player.getBag().addItemWithoutException(sd.getId(), sd.getCount(), Cause.SEVEN_DAYS_RESIGN);
		
		session.send(new SevenDaysResignInResponse(req.getSerial(), req.getDay(), getLeftResignInTimes(player)));
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_DAILY_SIGN, player);
		LOG.info("[7DAYRESIGN]ID[{}]DAY[{}]COST[{}]ITEM[{}]COUNT[{}]", player.getId(), index, resignCost, sd.getId(), sd.getCount());
	}
	
}
